

/*
Conversii utilizate in codul sursa
---------------------------------
	1. Toate componentele JLabel incep cu jlb*
	2. Toate componentele JPanel incep cu jpl*
	3. Toate componentele JButton incep cu jbn*
*/

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextArea;

/**
 * Clasa InterfataCalculator reprezinta interfata pentru programul de modelare a functilor
 * @author Sorica Alexandra
 */


public class InterfataCalculator extends JFrame implements ActionListener{
	
	/**
	 * serialVersionUID este o versiune identificator universal pentru o clasa serializabila.
	 * deserializarea foloseste acest numar pentru a se asigura ca o clasa incarcata corespunde
	 * exact la un obiect serializat.
	 */
	
	private static final long serialVersionUID = 1L;
	
	/**
	 * variabile
	 */
	
	final int MAX_INPUT_LENGTH = 20;
	final int INPUT_MODE = 0;
	final int RESULT_MODE = 1;
	final int ERROR_MODE = 2;
	int displayMode;

	boolean clearOnNextDigit, percent;
	double lastNumber;
	String lastOperator;
	
	private JLabel jlbOutput;
	private JButton jbnButtons[];
	private JPanel jplMaster,jplFunctii, jplControl;
	
	/**
	 * Font (String nume, stil int, int size)
	 * Creează un font nou de la numele specificat, stil şi dimensiune în puncte.
	 */
	
	Font f12 = new Font("Times New Roman", 1, 14);
	Font f121 = new Font("Times New Roman", 2, 14);
	
	/**
	 * Constructor
	 */
	
	public InterfataCalculator() 
	{
		
		/**
		 * Setez cadrul layout manager
		 */

		setBackground(Color.darkGray);

		jplMaster = new JPanel();

		jlbOutput = new JLabel("0");
		jlbOutput.setHorizontalTextPosition(JLabel.RIGHT);
		jlbOutput.setBackground(Color.WHITE);
		jlbOutput.setOpaque(true);
		
		/**
		 * Adaug componente in cadru
		 */
		
		getContentPane().add(jlbOutput, BorderLayout.NORTH);

		jbnButtons = new JButton[30];
		
		/**
		 * container pentru Jbuttons
		 */

		JPanel jplButtons = new JPanel();		

		/**
		 *  Creez Jbutton numeric
		 */
		
		for (int i=0; i<=9; i++)
		{
			/**
			 * setez fiecare eticheta Jbutton la valoarea indicelui
			 */
			
			jbnButtons[i] = new JButton(String.valueOf(i));
		}

		/**
		 * Creez operator Jbuttons
		 */
		
		jbnButtons[10] = new JButton("+/-");
		jbnButtons[11] = new JButton(".");
		jbnButtons[12] = new JButton("=");
		jbnButtons[13] = new JButton("/");
		jbnButtons[14] = new JButton("*");
		jbnButtons[15] = new JButton("-");
		jbnButtons[16] = new JButton("+");
		jbnButtons[17] = new JButton("Radical");
		jbnButtons[18] = new JButton("ln");
		jbnButtons[19] = new JButton("x");
		
		jplFunctii = new JPanel();
		jplFunctii.setLayout(new GridLayout(2, 2, 2, 2));

		jbnButtons[20] = new JButton("sin");
		jplFunctii.add(jbnButtons[20]);
		jbnButtons[23] = new JButton("cos");
		jplFunctii.add(jbnButtons[23]);
		jbnButtons[24] = new JButton("tg");
		jplFunctii.add(jbnButtons[24]);
		jbnButtons[25] = new JButton("ctg");
		jplFunctii.add(jbnButtons[25]);
		jbnButtons[26] = new JButton("arcsin");
		jplFunctii.add(jbnButtons[26]);
		jbnButtons[27] = new JButton("arccos");
		jplFunctii.add(jbnButtons[27]);
		jbnButtons[28] = new JButton("arctg");
		jplFunctii.add(jbnButtons[28]);
		jbnButtons[29] = new JButton("arcctg");
		jplFunctii.add(jbnButtons[29]);
		
		jplControl = new JPanel();
		jplControl.setLayout(new GridLayout(1, 2, 2 ,2));

		jbnButtons[21] = new JButton(" CE ");
		jbnButtons[22] = new JButton("C");

		jplControl.add(jbnButtons[21]);
		jplControl.add(jbnButtons[22]);
		
		/**
		 * Setez toate butoanele numerice albastre iar restul rosu
		 */
		
		for (int i=0; i<jbnButtons.length; i++)	{
			jbnButtons[i].setFont(f12);

			if (i<10)
				jbnButtons[i].setForeground(Color.blue);
				
			else
				jbnButtons[i].setForeground(Color.red);
		}
	
		/**
		 * Setam panoul layout sub forma unei matrici cu dimensiunea de 4 linii si 5 coloane
		 */
		
		jplButtons.setLayout(new GridLayout(4, 5, 2, 2));
		
		/**
		 * Adaug butoane la panoul de tastatura incepand din stanga sus
		 * primul rand
		 */
		
		for(int i=7; i<=9; i++)		{
			jplButtons.add(jbnButtons[i]);
		}
		
		/**
		 * Adaugare butoane, / si radical
		 */
		
		jplButtons.add(jbnButtons[13]);
		jplButtons.add(jbnButtons[17]);
		
		/**
		 * Randul 2
		 */
		
		for(int i=4; i<=6; i++)
		{
			jplButtons.add(jbnButtons[i]);
		}
		
		/**
		 * Adaugare butoane, * si ln
		 */
		jplButtons.add(jbnButtons[14]);
		jplButtons.add(jbnButtons[18]);

		/**
		 * Randul 3
		 */
		
		for( int i=1; i<=3; i++)
		{
			jplButtons.add(jbnButtons[i]);
		}
		
		/**
		 * Adaugam butoane - si x
		 */
		
		jplButtons.add(jbnButtons[15]);
		jplButtons.add(jbnButtons[19]);
		
		/**
		 * Randul 4
		 *  Adaugam 0, +/-, ., +, si =
		 */
		
		jplButtons.add(jbnButtons[0]);
		jplButtons.add(jbnButtons[10]);
		jplButtons.add(jbnButtons[11]);
		jplButtons.add(jbnButtons[16]);
		jplButtons.add(jbnButtons[12]);
		
		jplMaster.setLayout(new BorderLayout());
		jplMaster.add(jplFunctii, BorderLayout.NORTH);
		jplMaster.add(jplControl, BorderLayout.SOUTH);
		jplMaster.add(jplButtons, BorderLayout.CENTER);

		/**
		 * Adaug componente pe cadru
		 */
		
		getContentPane().add(jplMaster, BorderLayout.SOUTH);
		requestFocus();
		
		/**
		 * activez ActionListener
		 */
		
		for (int i=0; i<jbnButtons.length; i++){
			jbnButtons[i].addActionListener(this);
		}

		clearAll();

		/**
		 * Adaug WindowListener pentru inchiderea cadrului si se incheie programul
		 */
		
		addWindowListener(new WindowAdapter() {

				public void windowClosed(WindowEvent e)
				{
					System.exit(0);
				}
			}
		);
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
	}
	
	/**
	 * Terminarea constructorului InterfataCalculator
	 *  Perform action
	 */
	
	public void actionPerformed(ActionEvent e){	

		/**
		 * cauta daca butonul este apasat
		 */
		
		for (int i=0; i<jbnButtons.length; i++)
		{
			if(e.getSource() == jbnButtons[i])
			{
				switch(i)
				{
					case 0:		//0
						addDigitToDisplay(i);
						break;

					case 1:		//1
						addDigitToDisplay(i);
						break;

					case 2:		//2
						addDigitToDisplay(i);
						break;

					case 3:		//3
						addDigitToDisplay(i);
						break;

					case 4:		//4
						addDigitToDisplay(i);
						break;

					case 5:		//5
						addDigitToDisplay(i);
						break;

					case 6:		//6
						addDigitToDisplay(i);
						break;

					case 7:		//7
						addDigitToDisplay(i);
						break;

					case 8:		//8
						addDigitToDisplay(i);
						break;

					case 9:		//9
						addDigitToDisplay(i);
						break;

					case 10:	// +/-
						processSignChange();
						break;

					case 11:	// punct zecimal
						addDecimalPoint();
						break;

					case 12:	// =
						processEquals();
						break;

					case 13:	// /
						processOperator("/");
						break;

					case 14:	// *
						processOperator("*");
						break;

					case 15:	// -
						processOperator("-");
						break;

					case 16:	// +
						processOperator("+");
						break;

					case 17:	// radical
						
						break;

					case 18:	// ln
						
						break;

					case 19:	// x
						
						break;
						
					case 20:		//sin
						
						break;
						
					case 21:	// CE
						clearExisting();
						break;

					case 22:	// C
						clearAll();
						break;
						
					case 23:		//cos
						
						break;
						
					case 24:		//tg
						
						break;
						
					case 25:		//ctg
						
						break;
						
					case 26:		//arcsin
						
						break;
						
					case 27:		//arccos
						
						break;
						
					case 28:		//arctg
						
						break;
						
					case 29:		//arcctg
						
						break;
				}
			}
		}
	}

	void setDisplayString(String s){
		jlbOutput.setText(s);
	}

	String getDisplayString (){
		return jlbOutput.getText();
	}

	void addDigitToDisplay(int digit){
		if (clearOnNextDigit)
			setDisplayString("");

		String inputString = getDisplayString();
		
		if (inputString.indexOf("0") == 0){
			inputString = inputString.substring(1);
		}

		if ((!inputString.equals("0") || digit > 0)  && inputString.length() < MAX_INPUT_LENGTH){
			setDisplayString(inputString + digit);
		}
		

		displayMode = INPUT_MODE;
		clearOnNextDigit = false;
	}

	void addDecimalPoint(){
		displayMode = INPUT_MODE;

		if (clearOnNextDigit)
			setDisplayString("");

		String inputString = getDisplayString();
	
		/**
		 * Daca sirul de intrare contine deja un punct zecimal nu mai ia in 
		 * calcul inca unul
		 */
		if (inputString.indexOf(".") < 0)
			setDisplayString(new String(inputString + "."));
	}

	/**
	 * permite schimbarea semnului numarului curent
	 */
	
	void processSignChange(){
		if (displayMode == INPUT_MODE)
		{
			String input = getDisplayString();

			if (input.length() > 0 && !input.equals("0"))
			{
				if (input.indexOf("-") == 0)
					setDisplayString(input.substring(1));

				else
					setDisplayString("-" + input);
			}
			
		}

		else if (displayMode == RESULT_MODE)
		{
			double numberInDisplay = getNumberInDisplay();
		
			if (numberInDisplay != 0)
				displayResult(-numberInDisplay);
		}
	}

	void clearAll()	{
		setDisplayString("0");
		lastOperator = "0";
		lastNumber = 0;
		displayMode = INPUT_MODE;
		clearOnNextDigit = true;
	}

	/**
	 * permite curatarea casutei text
	 */
	
	void clearExisting(){
		setDisplayString("0");
		clearOnNextDigit = true;
		displayMode = INPUT_MODE;
	}

	double getNumberInDisplay()	{
		String input = jlbOutput.getText();
		return Double.parseDouble(input);
	}

	void processOperator(String op) {
		if (displayMode != ERROR_MODE)
		{
			double numberInDisplay = getNumberInDisplay();

			if (!lastOperator.equals("0"))	
			{
				try
				{
					double result = processLastOperator();
					displayResult(result);
					lastNumber = result;
				}

				catch (DivideByZeroException e)
				{
				}
			}
		
			else
			{
				lastNumber = numberInDisplay;
			}
			
			clearOnNextDigit = true;
			lastOperator = op;
		}
	}

	void processEquals(){
		double result = 0;

		if (displayMode != ERROR_MODE){
			try			
			{
				result = processLastOperator();
				displayResult(result);
			}
			
			catch (DivideByZeroException e)	{
				displayError("Cannot divide by zero!");
			}

			lastOperator = "0";
		}
	}

	double processLastOperator() throws DivideByZeroException {
		double result = 0;
		double numberInDisplay = getNumberInDisplay();

		if (lastOperator.equals("/"))
		{
			if (numberInDisplay == 0)
				throw (new DivideByZeroException());

			result = lastNumber / numberInDisplay;
		}
			
		if (lastOperator.equals("*"))
			result = lastNumber * numberInDisplay;

		if (lastOperator.equals("-"))
			result = lastNumber - numberInDisplay;

		if (lastOperator.equals("+"))
			result = lastNumber + numberInDisplay;

		return result;
	}

	void displayResult(double result){
		setDisplayString(Double.toString(result));
		lastNumber = result;
		displayMode = RESULT_MODE;
		clearOnNextDigit = true;
	}

	void displayError(String errorMessage){
		setDisplayString(errorMessage);
		lastNumber = 0;
		displayMode = ERROR_MODE;
		clearOnNextDigit = true;
	}

	public static void main(String args[]) {
		InterfataCalculator calci = new InterfataCalculator();
		calci.setTitle("InterfataCalculator");
		calci.setSize(241, 217);
		calci.pack();
		calci.setLocation(400, 250);
		calci.setVisible(true);
		calci.setResizable(false);
	}
	
}

class DivideByZeroException extends Exception{
	private static final long serialVersionUID = 1L;

	public DivideByZeroException()
	{
		super();
	}
	
	public DivideByZeroException(String s)
	{
		super(s);
	}
}

class CustomABOUTDialog extends JDialog implements ActionListener {
	private static final long serialVersionUID = 1L;
	JButton jbnOk;

	CustomABOUTDialog(JFrame parent, String title, boolean modal){
		super(parent, title, modal);
		setBackground(Color.black);
		
		JPanel p1 = new JPanel(new FlowLayout(FlowLayout.CENTER));

		StringBuffer text = new StringBuffer();
		
		JTextArea jtAreaAbout = new JTextArea(5, 21);
		jtAreaAbout.setText(text.toString());
		jtAreaAbout.setFont(new Font("Times New Roman", 1, 13));
		jtAreaAbout.setEditable(false);

		p1.add(jtAreaAbout);
		p1.setBackground(Color.red);
		getContentPane().add(p1, BorderLayout.CENTER);

		JPanel p2 = new JPanel(new FlowLayout(FlowLayout.CENTER));
		jbnOk = new JButton(" OK ");
		jbnOk.addActionListener(this);

		p2.add(jbnOk);
		getContentPane().add(p2, BorderLayout.SOUTH);

		setLocation(400, 250);
		setResizable(false);

		addWindowListener(new WindowAdapter() {
				public void windowClosing(WindowEvent e)
				{
					Window aboutDialog = e.getWindow();
					aboutDialog.dispose();
				}
			}
		);

		pack();
	}

	public void actionPerformed(ActionEvent e)
	{
		if(e.getSource() == jbnOk)	{
			this.dispose();
		}
	}
	
}